#include "widget.h"
#include "ui_widget.h"

#include <QtGui/private/qzipwriter_p.h> // 压缩   zip
#include <QtGui/private/qzipreader_p.h> // 解压缩 unzip

#include <QImage>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QStandardPaths> // 标准路径 例如 桌面

#include <QMenu>
#include <QCursor>        // 鼠标光标

#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 获取用户的配置文件目录
    QString configDir = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
    qDebug() << "Config directory: " << configDir;

    // 获取用户的文档目录
    QString documentsDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
    qDebug() << "Documents directory: " << documentsDir;

    // 获取用户的下载目录
    QString downloadDir = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
    qDebug() << "Download directory: " << downloadDir;

    // 获取用户的桌面目录
    QString DesktopLocationDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    this->myPath.dirPath = DesktopLocationDir;
    qDebug() << "DesktopLocationDir directory: " << DesktopLocationDir;


    // 文件浏览框添加删除按钮
    QMenu *mymenu = new QMenu(this);
    QAction *delFile = mymenu->addAction("清空");
    connect(delFile,&QAction::triggered,this,&Widget::clearTextBrowser);

    // 设置上下文菜单策略为Qt::CustomContextMenu
    ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
    // 连接customContextMenuRequested信号到槽函数
    connect(ui->textBrowser,&QTextBrowser::customContextMenuRequested,this,[=](const QPoint &pos){
        // 在鼠标位置显示上下文菜单选项按钮
        //mymenu->exec(QCursor::pos());
        // 方法2 推荐
        mymenu->exec(ui->textBrowser->mapToGlobal(pos));
    });

    /*
        在C++中，lambda表达式可以以两种方式捕获外部变量：通过引用和通过值。这两种捕获方式分别使用 [&] 和 [=] 符号来表示。

        1. [&] 符号表示按引用捕获：在 lambda 表达式中使用外部变量时，通过 [&] 捕获的外部变量以引用方式传递，【可以修改外部变量的值】。
        ```cpp
        int x = 1;
        auto func = [&]() {
            x = 2;
        };
        ```
        2. [=] 符号表示按值捕获：在 lambda 表达式中使用外部变量时，通过 [=] 捕获的外部变量以值传递方式传递，【不能修改外部变量的值】。
        ```cpp
        int x = 1;
        auto func = [=]() {
            int y = x;  // 可以访问 x 的值，但无法修改 x 的值
        };
        ```
        使用 [&] 和 [=] 的区别在于捕获的方式：[&] 按引用捕获变量，可以修改外部变量的值；[=] 按值捕获变量，不能修改外部变量的值。根据实际需求选择合适的捕获方式能够有效地控制 lambda 表达式对外部变量的影响。
    */
}

Widget::~Widget()
{
    delete ui;
}

// zip压缩 创建QZipWriter对象，并指定要创建的zip文件路径
void Widget::on_PB_zip_clicked()
{
    // 获取用户的桌面目录
    myPath.dirPath = QFileDialog::getExistingDirectory(this,"打开目录",myPath.dirPath);
    qDebug()<<"myPath.dirPath = "<<myPath.dirPath;

    ui->textBrowser->append("===============压缩文件==================");
    this->zip();
}

void Widget::zip()
{
    QString zip;

    // 将目录下的文件压缩 以压缩的命令作为压缩名
    if (QFileInfo(this->myPath.dirPath).isDir()) {
        zip = this->myPath.dirPath + QString("/%1.zip").arg(QFileInfo(this->myPath.dirPath + "/").dir().dirName());
        this->myPath.zipPath = this->myPath.dirPath;
    }
    else {
        zip = this->myPath.filePath;
    }
    qDebug()<<"zip = "<<zip;
    // 压缩的文件后缀必须是.zip
    if (!zip.endsWith(".zip")) return;

    QZipWriter zipWriter(zip);

    // 压缩目录
    QDir dir(this->myPath.zipPath);

    // 获取文件夹下的所有文件
    QStringList filters;
    QFileInfoList imageFiles = dir.entryInfoList(filters, QDir::Files | QDir::Dirs);
    for(const QFileInfo& fileInfo:imageFiles) {

        // 跳过. 和 ..
        if (fileInfo.fileName() == "." || fileInfo.fileName() == "..") {
            continue;
        }

        if (fileInfo.isFile()) {
            // 传入文件绝对路径
            QFile file(fileInfo.filePath());

            // 打开失败的文件跳过
            if (!file.open(QIODevice::ReadOnly)) {
                qWarning()<< "文件打开失败: "<<file.fileName();
                continue;
            }

            // 从原始文件路径提取相对路径，作为zip文件中的目录结构
            /* 案例：
                QDir dir("/home/bob");
                QString s;

                s = dir.relativeFilePath("images/file.jpg");     // s is "images/file.jpg"
                s = dir.relativeFilePath("/home/mary/file.txt"); // s is "../mary/file.txt"
            */
            QString relativePath = dir.relativeFilePath(fileInfo.absoluteFilePath());
            // 跳过同名的压缩文件
            if (zip.contains(relativePath)) {
                continue;
            }
            // 添加相对路径到zip文件中，并将对应的数据流写入
            zipWriter.addFile(relativePath,file.readAll());


           // 关闭文件
           file.close();

           qDebug() << "压缩文件相对路径:" << relativePath;
           ui->textBrowser->append("压缩文件:" + relativePath);
        }
        else if (fileInfo.isDir()) {
            // 暂不处理
        }
    }


    // 关闭ZIP
    zipWriter.close();
    qDebug() << "压缩完成。";
    ui->textBrowser->append("压缩完成。");
}


// zip解压缩
void Widget::on_PB_unzip_clicked()
{
    ui->textBrowser->append("===============解压文件==================");
    QString unzip = QFileDialog::getOpenFileName(this,"打开文件",this->myPath.dirPath,"文件 (*.zip *.txt);;图片 (*.png *.bpm *.jpg);;XML 文件 (*.xml)");
    qDebug()<<"解压文件 ： "<<unzip;
    QZipReader zipReader(unzip);
     //reader.extractAll(path); // 指定解压目录

    for(auto fileInfo:zipReader.fileInfoList())
    {
        if(fileInfo.isFile) {
            // 文件的绝对路径
            QFile file(this->myPath.dirPath + "/" + fileInfo.filePath);
            ui->textBrowser->append("解压文件：" + fileInfo.filePath);
            // 打开失败的文件跳过
            if (!file.open(QIODevice::WriteOnly)) {
                qWarning()<< "文件打开失败: "<<file.fileName();
                continue;
            }

            // 注意编码问题
            QByteArray dt = fileInfo.filePath.toUtf8();
            QString strtemp = QString::fromLocal8Bit(dt);

            QByteArray array = zipReader.fileData(strtemp);
            file.write(array);
            file.close();
        }
        else if(fileInfo.isDir)
        {
           // 暂不处理
        }
    }

    // 关闭UNZIP
    zipReader.close();
}

// 创建文件夹[暂未使用]
bool Widget::CreateFolder(const QString& folderPath)
{
    qDebug()<<"CreateFolder 创建目录 = "<<folderPath;

    bool state = false;
#ifndef Q_OS_WIN
    // 创建文件夹
    QDir dir(folderPath);
    if (!dir.exists())
    {
        return dir.mkdir(folderPath);
    }else{
        state = true;
    }
#else
    QDir tempDir(folderPath);
    if (tempDir.exists()) {
        // 删除该目录，包括其所有内容。成功时返回true，否则返回false。
        // tempDir.removeRecursively();
       state = true;
    }
    else {
        // 创建目录路径目录
        state =  tempDir.mkpath(folderPath);
        qDebug()<<"创建目录 = "<<folderPath<<" state = "<<state;
    }

#endif
    return state;
}

// 清空 QtextBrowser
void Widget::clearTextBrowser()
{
    qDebug()<<"清空";
    ui->textBrowser->clear();
}


